using UnityEngine;
using System.Collections;

/* UIEffect is the base class for small fancy UI effects.
 * It's basically a player which can be paused, resumed, restarted etc.
 * It supports easing functions and effect duration modifications on-the-fly.
 * 
 * Implement the EffectUpdate to code your effect.
 * TODO: arguments
 * TODO: speed
 * TODO: backwards speed
 */ 

public abstract class UIEffectTemplate : MonoBehaviour
{

	public delegate void EffectEndedDelegate( bool a_bEffectPlayedForward );
	protected UIEffectTemplate.EffectEndedDelegate m_dEffectEndedDelegate;

	protected float m_fSpeed;
	protected float m_fTimer;
	protected float m_fDuration;
	protected bool m_bIsPlaying;

	protected gkInterpolate.EaseType m_eEasingType = gkInterpolate.EaseType.Linear;
	protected gkInterpolate.EaseFunction m_dEasingFunction;

	public virtual float time
	{
		get
		{
			return m_fTimer;
		}
		set
		{
			m_fTimer = Mathf.Clamp( value, 0.0f, m_fDuration );
			EffectUpdate( );
		}
	}

	public virtual float duration
	{
		get
		{
			return m_fDuration;
		}
		set
		{
			if( value >= 0.0f )
			{
				m_fDuration = value;
				m_fTimer = Mathf.Min( m_fTimer, value );
			}
		}
	}

	public bool isPlaying
	{
		get
		{
			return m_bIsPlaying;
		}
	}

	public gkInterpolate.EaseType easing
	{
		get
		{
			return m_eEasingType;
		}
		set
		{
			m_eEasingType = value;
			m_dEasingFunction = gkInterpolate.Ease( value );
		}
	}

	public bool isPlayingForward
	{
		get
		{
			return m_fSpeed > 0.0f;
		}
	}

	public UIEffectTemplate.EffectEndedDelegate effectEndedDelegate
	{
		get
		{
			return m_dEffectEndedDelegate;
		}
		set
		{
			m_dEffectEndedDelegate = value;
		}
	}
	
	public void Init( )
	{
		InternalInit( );
		EffectUpdate( );
	}

	protected virtual void InternalInit( )
	{
		m_dEffectEndedDelegate = null;
		m_fSpeed = 1.0f;
		m_fTimer = 0.0f;
		m_fDuration = 1.0f;
		m_bIsPlaying = false;
		m_dEasingFunction = gkInterpolate.Ease( m_eEasingType );
	}

	void LateUpdate( )
	{
		if( m_bIsPlaying == true )
		{
			EffectUpdate( );
			TimerUpdate( );
		}
	}

	public virtual void Pause( )
	{
		m_bIsPlaying = false;
	}

	public virtual void Play( )
	{
		m_fSpeed = 1.0f;
		m_bIsPlaying = true;
	}

	// Restarts effect with initial settings and plays it
	public virtual void Restart( )
	{
		if( m_fSpeed < 0.0f )
		{
			m_fTimer = m_fDuration;
		}
		else
		{
			m_fTimer = 0.0f;
		}

		m_bIsPlaying = true;
	}

	// Resets effect with initial settings, updates it once
	// but doesn't start it if not playing
	public virtual void ResetAndStop( )
	{
		if( m_fSpeed < 0.0f )
		{
			m_fTimer = m_fDuration;
		}
		else
		{
			m_fTimer = 0.0f;
		}

		EffectUpdate( );
	}

	// Reverse the effect backwards
	public virtual void PlayBackwards( )
	{
		m_bIsPlaying = true;
		m_fSpeed = -1.0f;
	}

	protected virtual void TimerUpdate( )
	{
		float fPreviousEffectTimer = m_fTimer;

		// Clamps timer
		m_fTimer = Mathf.Clamp( m_fTimer + m_fSpeed * Time.deltaTime, 0.0f, m_fDuration );

		// Stops update if needed
		if( fPreviousEffectTimer == m_fTimer && ( m_fTimer == 0.0f || m_fTimer == m_fDuration ) )
		{
			m_bIsPlaying = false;

			if( m_dEffectEndedDelegate != null )
			{
				m_dEffectEndedDelegate( m_fSpeed == 1.0f );
			}
		}
	}

	abstract protected void EffectUpdate( );
}